package com.cain.DontTapTheWhiteTile.activity;

import android.content.DialogInterface;
import android.content.Intent;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.cain.DontTapTheWhiteTile.R;
import com.cain.DontTapTheWhiteTile.bean.Block;
import com.cain.DontTapTheWhiteTile.render.GameBoardRender;
import com.cain.DontTapTheWhiteTile.tool.Constants;
import com.cain.DontTapTheWhiteTile.tool.MyCallBack;
import com.cain.DontTapTheWhiteTile.tool.MyNumber;
import com.cain.DontTapTheWhiteTile.tool.MyString;
import com.cain.DontTapTheWhiteTile.view.CustomDialog;

import java.util.Map;
import java.util.Random;

public class GameControllerActivity extends AppCompatActivity implements MyCallBack, Runnable {
    private static final String TAG = "GameControllerActivity";

    private RelativeLayout gameBoard;
    private GLSurfaceView glSurfaceView;
    private TextView textView;   //计时器

    private int mode;   //游戏模式
    private int difficulty;   //游戏难度
    private Block[][] blockArray = null;
    private GameBoardRender render;
    private float blockWidth;   //块宽度
    private float blockHeight;   //块长度

    private boolean isGameBegin;   //游戏是否开始
    private boolean isGameOver;   //游戏是否结束
    private float speed;   //游戏速度
    private int maxCount;   //总格子数
    private int loadedCount;   //当前已加载格子数
    private int tapCount;   //已点击格子数
    private float moveDistance;   //需要移动的距离
    private int currentRow;   //当前可点击行
    private Block lastBlock;   //上次点击后的块
    private long beginTime;   //游戏开始时间
    private long endTime;   //游戏结束时间

    private static final int GAME_END_NORMAL = 0;   //正常的游戏结束
    private static final int GAME_END_WRONG = 1;   //点击错误的结束

    /**
     * 刷新UI
     */
    public static final int TEXT_UPDATE = 0;   //更新计时器
    public static final int GAME_OVER = 1;   //游戏结束
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case TEXT_UPDATE:
                    switch (mode) {
                        case Constants.GAME_MODE_CLASSIC:
                            endTime = System.currentTimeMillis();
                            textView.setText(MyString.timeFormatToString(MyNumber.millisToFormat(endTime - beginTime)));
                            break;

                        case Constants.GAME_MODE_ARCADE:
                            textView.setText(String.valueOf(tapCount));
                            if (tapCount % 20 == 0)
                                speed += 0.001;
                            break;
                    }
                    break;
                
                case GAME_OVER:
                    showDialog();
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        mode = intent.getIntExtra("mode", Constants.GAME_MODE_CLASSIC);
        difficulty = intent.getIntExtra("difficulty", Constants.GAME_DIFFICULTY_EASY);
        maxCount = intent.getIntExtra("count", Constants.GAME_COUNT_UNLIMITED);

        setContentView(R.layout.activity_game_controller);
        gameBoard = (RelativeLayout) findViewById(R.id.game_controller_board);
        textView = (TextView) findViewById(R.id.game_controller_text);

        gameInit();

        glSurfaceView = new GLSurfaceView(this);
        glSurfaceView.setEGLContextClientVersion(2);
        render = new GameBoardRender(blockArray, this);
        glSurfaceView.setRenderer(render);
        gameBoard.addView(glSurfaceView, new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
                RelativeLayout.LayoutParams.MATCH_PARENT));
        glSurfaceView.setOnTouchListener(onTouchListener);
    }

    /**
     * 游戏初始化
     */
    private void gameInit() {
        if (blockArray == null) {
            switch (difficulty) {
                case Constants.GAME_DIFFICULTY_EASY:
                    blockArray = new Block[5][4];
                    break;

                case Constants.GAME_DIFFICULTY_NORMAL:
                    blockArray = new Block[6][5];
                    break;

                case Constants.GAME_DIFFICULTY_HARD:
                    blockArray = new Block[7][6];
                    break;
            }
        }
        resetAll(blockArray);
        switch (mode) {
            case Constants.GAME_MODE_CLASSIC:
                speed = 0.05f;
                moveDistance = 0;
                beginTime = -1;
                tapCount = 0;
                textView.setText("0.000''");
                isGameBegin = false;   //游戏是否开始
                isGameOver = false;   //游戏是否结束
                break;

            case Constants.GAME_MODE_ARCADE:
                speed = 0.025f;
                tapCount = 0;
                textView.setText("0");
                isGameBegin = false;   //游戏是否开始
                isGameOver = false;   //游戏是否结束
                break;
        }
    }

    /**
     * 全部重置
     * @param blockArray
     */
    private void resetAll(Block[][] blockArray) {
        blockWidth = 2.0f / blockArray[0].length;
        blockHeight = 2.0f / (blockArray.length - 1);
        int startLocation = blockArray.length - (blockArray.length - 1) / 3 - 1;
        Random random = new Random();
        for (int i = 0; i < blockArray.length; ++i) {
            for (int j = 0; j < blockArray[i].length; ++j) {
                blockArray[i][j] = new Block(blockWidth * j - 1.0f,
                        -blockHeight * (i - 1) + 1.0f,
                        blockWidth * (j + 1) - 1.0f,
                        -blockHeight * i + 1.0f,
                        Constants.BLOCK_WHITE,
                        Block.CLICKABLE_NOT);
                if (i > startLocation) {
                    blockArray[i][j].color = Constants.BLOCK_YELLOW;
                }
            }
            if (i <= startLocation) {
                int index = random.nextInt(blockArray[i].length);
                blockArray[i][index].color = Constants.BLOCK_BLACK;
                if (i == startLocation)
                    blockArray[i][index].state = Block.CLICKABLE_RIGHT;
            }
        }
        loadedCount = startLocation + 1;
        currentRow = startLocation;
    }

    /**
     * 重置一行
     * @param index
     */
    private void resetRow(int index) {
        Block[] row = blockArray[index];
        Block[] nextRow = blockArray[(index + 1) % blockArray.length];
        for (int i = 0; i < row.length; ++i) {
            if (mode == Constants.GAME_MODE_ARCADE && row[i].state == Block.CLICKABLE_RIGHT) {
                lastBlock = row[i];
                gameOver(GAME_END_NORMAL);
                return;
            } else if (mode == Constants.GAME_MODE_ARCADE && row[i].state == Block.CLICKABLE_WRONG) {

            } else {
                row[i].moveTo(row[i].left, nextRow[0].top);
                row[i].color = Constants.BLOCK_WHITE;
                row[i].state = Block.CLICKABLE_NOT;
            }
        }
        Random random = new Random();
        index = random.nextInt(row.length);
        row[index].color = Constants.BLOCK_BLACK;
    }

    /**
     * 检查是否有行越过底部，如果有则让其返回顶部
     */
    private void check() {
        int index;
        for (index = 0; index < blockArray.length; ++index) {
            if (blockArray[index][0].top <= -1) {
                if (maxCount == Constants.GAME_COUNT_UNLIMITED || loadedCount < maxCount) {
                    resetRow(index);
                    loadedCount++;
                    break;
                }
            }
        }
    }

    /**
     * 使一行有效
     * @param index
     */
    private void enableRow(int index) {
        for (int j = 0; j < blockArray[index].length; ++j) {
            if (blockArray[index][j].color == Constants.BLOCK_WHITE)
                blockArray[index][j].state = Block.CLICKABLE_WRONG;
            else
                blockArray[index][j].state = Block.CLICKABLE_RIGHT;
        }
    }

    /**
     * 使一行失效
     * @param index 行号
     * @param block 黑色的块
     */
    private void disableRow(int index, Block block) {
        for (int j = 0; j < blockArray[index].length; ++j) {
            blockArray[index][j].state = Block.CLICKABLE_NOT;
        }
        block.color = Constants.BLOCK_GRAY;
    }

    /**
     * 获得点击范围的具体下标
     * @param x
     * @param y
     * @return
     */
    private int getColumnIndex(float x, float y) {
        int length = blockArray.length - 1;
        int width = glSurfaceView.getWidth() / length;
        int height = glSurfaceView.getHeight() / length;
        int temp = length / 3 + 1;   //从后往前数能点击的块数
        int minTop = (int) (glSurfaceView.getHeight() - height * (temp + 0.5));
        int maxBottom = (int) (glSurfaceView.getHeight() - height * (temp - 1.5));
        int top = glSurfaceView.getHeight() - height * temp;
        int bottom = glSurfaceView.getHeight() - height * (temp - 1);
        if (y >= minTop && y <= maxBottom) {
            for (int j = 0; j < blockArray[currentRow].length; j++) {
                if (x >= j * width && x <= (j + 1) * width) {
                    if (blockArray[currentRow][j].state == Block.CLICKABLE_RIGHT)
                        return j;
                    else if (y <= top || y >= bottom)
                        return -1;
                    else
                        return j;
                }
            }
            return -1;
        } else
            return -1;
    }

    /**
     * 点击事件处理
     */
    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (isGameOver) return false;
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                switch (mode) {
                    case Constants.GAME_MODE_CLASSIC: {
                        float x = event.getX();
                        float y = event.getY();
                        int column = getColumnIndex(x, y);
                        if (column == -1)
                            return false;
                        else {
                            lastBlock = blockArray[currentRow][column];
                            switch (lastBlock.state) {
                                case Block.CLICKABLE_RIGHT:
                                    Log.i(TAG, "可点击：黑色");
                                    tapCount++;
                                    if (isGameBegin) {
                                        disableRow(currentRow, lastBlock);
                                        currentRow = (currentRow + blockArray.length - 1) % blockArray.length;
                                        moveDistance += blockHeight;
                                        enableRow(currentRow);
                                        if (tapCount == maxCount)
                                            gameOver(GAME_END_NORMAL);
                                    } else {
                                        gameBegin();
                                        moveDistance += blockHeight;
                                        currentRow = (currentRow + blockArray.length - 1) % blockArray.length;
                                    }
                                    break;

                                case Block.CLICKABLE_WRONG:
                                    Log.i(TAG, "可点击：白色");
                                    gameOver(GAME_END_WRONG);
                                    break;

                                case Block.CLICKABLE_NOT:
                                    Log.i(TAG, "不能点击");
                                    break;
                            }
                        }
                    }
                    break;

                    case Constants.GAME_MODE_ARCADE: {
                        float x = event.getX() / glSurfaceView.getWidth() * 2.0f - 1.0f;
                        float y = -event.getY() / glSurfaceView.getHeight() * 2.0f + 1.0f;
                        int index;
                        for (index = 0; index < blockArray.length; ++index) {
                            if (blockArray[index][0].inLine(y)) {
                                for (int j = 0; j < blockArray[index].length; ++j) {
                                    if (blockArray[index][j].contains(x, y)) {
                                        lastBlock = blockArray[index][j];
                                        break;
                                    }
                                }
                                break;
                            }
                        }
                        switch (lastBlock.state) {
                            case Block.CLICKABLE_RIGHT:
                                Log.i(TAG, "可点击：黑色");
                                tapCount++;
                                if (isGameBegin) {
                                    disableRow(index, lastBlock);
                                    enableRow((index + blockArray.length - 1) % blockArray.length);
                                } else {
                                    gameBegin();
                                    moveDistance += blockHeight;
                                    currentRow = (currentRow + blockArray.length - 1) % blockArray.length;
                                }
                                handler.sendEmptyMessage(TEXT_UPDATE);
                                break;

                            case Block.CLICKABLE_WRONG:
                                Log.i(TAG, "可点击：白色");
                                gameOver(GAME_END_WRONG);
                                break;

                            case Block.CLICKABLE_NOT:
                                Log.i(TAG, "不能点击");
                                break;
                        }
                    }
                    break;
                }
            }
            return true;
        }
    };

    /**
     * 游戏开始
     */
    private void gameBegin() {
        int startLocation = blockArray.length - (blockArray.length - 1) / 3 - 1;
        for (int i = 0; i <= startLocation; ++i) {
            for (int j = 0; j < blockArray[i].length; ++j) {
                if (i != startLocation) {
                    if (blockArray[i][j].color == Constants.BLOCK_WHITE) {
                        blockArray[i][j].state = Block.CLICKABLE_WRONG;
                    } else {
                        blockArray[i][j].state = Block.CLICKABLE_RIGHT;
                    }
                } else {
                    if (blockArray[i][j].state == Block.CLICKABLE_RIGHT) {
                        blockArray[i][j].state = Block.CLICKABLE_NOT;
                        blockArray[i][j].color = Constants.BLOCK_GRAY;
                        break;
                    }
                }
            }
        }
        beginTime = System.currentTimeMillis();
        isGameBegin = true;
    }

    /**
     * 游戏结束
     * @param overType 结束类型
     */
    private void gameOver(int overType) {
        isGameOver = true;
        switch (overType) {
            case GAME_END_NORMAL:
                switch (mode) {
                    case Constants.GAME_MODE_CLASSIC:
                        String modeDifficulty = Constants.BEST_CLASSIC_EASY_FEW;
                        long history;
                        long score;
                        switch (difficulty) {
                            case Constants.GAME_DIFFICULTY_EASY:
                                if (maxCount == Constants.GAME_COUNT_FEW)
                                    modeDifficulty = Constants.BEST_CLASSIC_EASY_FEW;
                                else
                                    modeDifficulty = Constants.BEST_CLASSIC_EASY_MUCH;
                                break;
                            case Constants.GAME_DIFFICULTY_NORMAL:
                                if (maxCount == Constants.GAME_COUNT_FEW)
                                    modeDifficulty = Constants.BEST_CLASSIC_NORMAL_FEW;
                                else
                                    modeDifficulty = Constants.BEST_CLASSIC_NORMAL_MUCH;
                                break;
                            case Constants.GAME_DIFFICULTY_HARD:
                                if (maxCount == Constants.GAME_COUNT_FEW)
                                    modeDifficulty = Constants.BEST_CLASSIC_HARD_FEW;
                                else
                                    modeDifficulty = Constants.BEST_CLASSIC_HARD_MUCH;
                                break;
                        }
                        history = Constants.getLong(modeDifficulty, 0);
                        score = endTime - beginTime;
                        if (history == 0 || score < history) {
                            Constants.put(modeDifficulty, score);
                        }
                        Intent intent = new Intent(this, ResultActivity.class);
                        intent.putExtra("mode", modeDifficulty);
                        intent.putExtra("history", history);
                        intent.putExtra("score", score);
                        intent.putExtra("state", Constants.GAME_OVER_NORMAL);
                        startActivityForResult(intent, 0);
                        break;

                    case Constants.GAME_MODE_ARCADE:
                        Thread thread = new Thread(GameControllerActivity.this);
                        thread.start();
                        break;
                }
                break;

            case GAME_END_WRONG:
                lastBlock.color = Constants.BLOCK_RED;
                Thread thread = new Thread(GameControllerActivity.this);
                thread.start();
                break;
        }
    }

    /**
     * 全体向上或向下移动distance的距离
     * @param distance
     */
    private void moveAll(float distance) {
        for (int i = 0; i < blockArray.length; ++i) {
            for (int j = 0; j < blockArray[i].length; ++j) {
                blockArray[i][j].move(0, distance);
            }
        }
    }

    /**
     * 普通回调
     */
    @Override
    public void execute() {

    }

    /**
     * 带参数的回调
     * @param tag 身份
     * @param params 参数
     */
    @Override
    public void execute(String tag, Map<String, Object> params) {
        if (tag.equals("GameBoardRender")) {
            if (isGameBegin && !isGameOver) {
                switch (mode) {
                    case Constants.GAME_MODE_CLASSIC:
                        if (Math.abs(moveDistance) <= speed) {
                            moveAll(-moveDistance);
                            moveDistance = 0;
                        } else {
                            moveAll(-speed);
                            moveDistance -= speed;
                        }
                        check();
                        handler.sendEmptyMessage(TEXT_UPDATE);
                        break;

                    case Constants.GAME_MODE_ARCADE:
                        moveAll(-speed);
                        check();
                        break;
                }
            }
        }
    }

    /**
     * 如果点错了或者错过了则闪烁错误的那块
     */
    @Override
    public void run() {
        try {
            if (lastBlock.color == Constants.BLOCK_RED) {
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_WHITE;
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_RED;
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_WHITE;
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_RED;
                handler.sendEmptyMessage(GAME_OVER);
            } else {
                int blockCount = (blockArray.length - 1) / 3 + 1;
                float sp = blockCount * blockHeight / 20;
                for (int i = 0; i < 20; i++) {
                    Thread.sleep(10);
                    moveAll(sp);
                }
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_WHITE;
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_BLACK;
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_WHITE;
                Thread.sleep(150);
                lastBlock.color = Constants.BLOCK_BLACK;
                handler.sendEmptyMessage(GAME_OVER);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 显示游戏结束之后的弹窗
     */
    private void showDialog() {
        CustomDialog.Builder builder = new CustomDialog.Builder(this);
        final Intent intent = new Intent(this, ResultActivity.class);
        
        String title = null;
        String message = null;
        String modeDifficulty = Constants.BEST_CLASSIC_EASY_FEW;
        long history;
        long score;
        switch (mode) {
            case Constants.GAME_MODE_CLASSIC:
                switch (difficulty) {
                    case Constants.GAME_DIFFICULTY_EASY:
                        if (maxCount == Constants.GAME_COUNT_FEW)
                            modeDifficulty = Constants.BEST_CLASSIC_EASY_FEW;
                        else
                            modeDifficulty = Constants.BEST_CLASSIC_EASY_MUCH;
                        break;
                    case Constants.GAME_DIFFICULTY_NORMAL:
                        if (maxCount == Constants.GAME_COUNT_FEW)
                            modeDifficulty = Constants.BEST_CLASSIC_NORMAL_FEW;
                        else
                            modeDifficulty = Constants.BEST_CLASSIC_NORMAL_MUCH;
                        break;
                    case Constants.GAME_DIFFICULTY_HARD:
                        if (maxCount == Constants.GAME_COUNT_FEW)
                            modeDifficulty = Constants.BEST_CLASSIC_HARD_FEW;
                        else
                            modeDifficulty = Constants.BEST_CLASSIC_HARD_MUCH;
                        break;
                }
                history = Constants.getLong(modeDifficulty, 0);
                score = 0;
                title = "败了";
                message = "历史最佳" + MyString.timeFormatToString(MyNumber.millisToFormat(history));
                intent.putExtra("mode", modeDifficulty);
                intent.putExtra("history", history);
                intent.putExtra("score", score);
                intent.putExtra("state", Constants.GAME_OVER_WRONG);
                break;
            
            case Constants.GAME_MODE_ARCADE:
                switch (difficulty) {
                    case Constants.GAME_DIFFICULTY_EASY:
                        modeDifficulty = Constants.BEST_ARCADE_EASY;
                        break;
                    case Constants.GAME_DIFFICULTY_NORMAL:
                        modeDifficulty = Constants.BEST_ARCADE_NORMAL;
                        break;
                    case Constants.GAME_DIFFICULTY_HARD:
                        modeDifficulty = Constants.BEST_ARCADE_HARD;
                        break;
                }
                history = Constants.getLong(modeDifficulty, 0);
                score = tapCount;
                if (score > history) {
                    Constants.put(modeDifficulty, score);
                    message = "新纪录";
                } else {
                    message = "历史最佳" + history;
                }
                title = String.valueOf(score);
                intent.putExtra("mode", modeDifficulty);
                intent.putExtra("history", history);
                intent.putExtra("score", score);
                if (lastBlock.color == Constants.BLOCK_RED)
                    intent.putExtra("state", Constants.GAME_OVER_WRONG);
                else
                    intent.putExtra("state", Constants.GAME_OVER_NORMAL);
                break;
        }

        builder.setTitle(title);
        builder.setMessage(message);

        builder.setPositiveButton("结束", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                startActivityForResult(intent, 0);
            }
        });

        CustomDialog dialog = builder.create();
        dialog.setCanceledOnTouchOutside(false);

        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                dialog.dismiss();
                startActivityForResult(intent, 0);
            }
        });

        dialog.show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (resultCode) {
            case ResultActivity.RESULT_MAIN:
                finish();
                break;

            case ResultActivity.RESULT_RESTART:
                gameInit();
                break;
        }
    }
}
